﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Styx.CommonBot.Routines;
using Styx.Pathing;
using Styx;
using Styx.WoWInternals.WoWObjects;
using Styx.WoWInternals;
using Styx.CommonBot;
using System.Windows.Media;
using Styx.Common;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using Styx.TreeSharp;
using Action = Styx.TreeSharp.Action;
using System.Diagnostics;
using System.Threading;
using Styx.WoWInternals.Misc;

namespace MyBMHunter
{
    public partial class Main : CombatRoutine
    {
        private static Stopwatch fightTimer = new Stopwatch();
        private static Stopwatch pullTimer = new Stopwatch();
        private static Stopwatch petPresenceTimer = new Stopwatch();
        private static ulong lastGuid = 0;

        #region Buff Checks

        public bool buffExists(int Buff, WoWUnit onTarget)
        {
            if (onTarget != null)
            {
                var Results = onTarget.GetAuraById(Buff);
                if (Results != null)
                    return true;
            }
            return false;
        }

        public double buffTimeLeft(int Buff, WoWUnit onTarget)
        {
            if (onTarget != null)
            {
                var Results = onTarget.GetAuraById(Buff);
                if (Results != null)
                {
                    if (Results.TimeLeft.TotalMilliseconds > 0)
                        return Results.TimeLeft.TotalMilliseconds;
                }
            }
            return 0;
        }

        public bool buffExists(string Buff, WoWUnit onTarget)
        {
            if (onTarget != null)
            {
                var Results = onTarget.GetAuraByName(Buff);
                if (Results != null)
                    return true;
            }
            return false;
        }

        public double buffTimeLeft(string Buff, WoWUnit onTarget)
        {
            if (onTarget != null)
            {
                var Results = onTarget.GetAuraByName(Buff);
                if (Results != null)
                {
                    if (Results.TimeLeft.TotalMilliseconds > 0)
                        return Results.TimeLeft.TotalMilliseconds;
                }
            }
            return 0;
        }



        public uint buffStackCount(int Buff, WoWUnit onTarget)
        {
            if (onTarget != null)
            {
                var Results = onTarget.GetAuraById(Buff);
                if (Results != null)
                    return Results.StackCount;
            }
            return 0;
        }
        public uint buffStackCount(string Buff, WoWUnit onTarget)
        {
            if (onTarget != null)
            {
                var Results = onTarget.GetAuraByName(Buff);
                if (Results != null)
                    return Results.StackCount;
            }
            return 0;
        }
        #endregion

        #region Cache Checks
        public IEnumerable<WoWAura> cachedAuras = new List<WoWAura>();
        public IEnumerable<WoWAura> cachedTargetAuras = new List<WoWAura>();
        public void getCachedAuras()
        {
            if (Me.CurrentTarget != null)
                cachedTargetAuras = Me.CurrentTarget.GetAllAuras();
            cachedAuras = Me.GetAllAuras();
        }
        #endregion

        #region Cooldown Checks
        private Dictionary<WoWSpell, long> Cooldowns = new Dictionary<WoWSpell, long>();
        public TimeSpan cooldownLeft(int Spell)
        {
            SpellFindResults Results;
            if (SpellManager.FindSpell(Spell, out Results))
            {
                WoWSpell Result = Results.Override ?? Results.Original;
                if (Cooldowns.TryGetValue(Result, out lastUsed))
                {
                    if (DateTime.Now.Ticks < lastUsed)
                        return Result.CooldownTimeLeft;
                    return TimeSpan.MaxValue;
                }
            }
            return TimeSpan.MaxValue;
        }
        public TimeSpan cooldownLeft(string Spell)
        {
            SpellFindResults Results;
            if (SpellManager.FindSpell(Spell, out Results))
            {
                WoWSpell Result = Results.Override ?? Results.Original;
                if (Cooldowns.TryGetValue(Result, out lastUsed))
                {
                    if (DateTime.Now.Ticks < lastUsed)
                        return Result.CooldownTimeLeft;
                    return TimeSpan.MaxValue;
                }
            }
            return TimeSpan.MaxValue;
        }
        long lastUsed;
        public int lastCast;
        public bool onCooldown(int Spell)
        {
            SpellFindResults Results;
            if (SpellManager.FindSpell(Spell, out Results))
            {
                WoWSpell Result = Results.Override ?? Results.Original;
                if (Cooldowns.TryGetValue(Result, out lastUsed))
                {
                    if (DateTime.Now.Ticks < lastUsed)
                        return Result.Cooldown;
                    return false;
                }
            }
            return false;
        }
        public bool onCooldown(string Spell)
        {
            SpellFindResults Results;
            if (SpellManager.FindSpell(Spell, out Results))
            {
                WoWSpell Result = Results.Override ?? Results.Original;
                if (Cooldowns.TryGetValue(Result, out lastUsed))
                {
                    if (DateTime.Now.Ticks < lastUsed)
                        return Result.Cooldown;
                    return false;
                }
            }
            return false;
        }
        public TimeSpan spellCooldownLeft(int Spell, bool useTracker = false)
        {
            if (useTracker)
                return cooldownLeft(Spell);
            SpellFindResults results;
            if (SpellManager.FindSpell(Spell, out results))
            {
                if (results.Override != null)
                    return results.Override.CooldownTimeLeft;
                return results.Override.CooldownTimeLeft;
            }
            return TimeSpan.MaxValue;
        }
        public TimeSpan spellCooldownLeft(string Spell, bool useTracker = false)
        {
            if (useTracker)
                return cooldownLeft(Spell);
            SpellFindResults results;
            if (SpellManager.FindSpell(Spell, out results))
            {
                if (results.Override != null)
                    return results.Override.CooldownTimeLeft;
                return results.Override.CooldownTimeLeft;
            }
            return TimeSpan.MaxValue;
        }
        public bool spellOnCooldown(int Spell, bool useTracker = false)
        {
            if (useTracker)
                return !onCooldown(Spell);
            SpellFindResults results;
            if (SpellManager.FindSpell(Spell, out results))
                return results.Override != null ? results.Override.Cooldown : results.Original.Cooldown;
            return false;
        }
        public bool spellOnCooldown(string Spell, bool useTracker = false)
        {
            if (useTracker)
                return !onCooldown(Spell);
            SpellFindResults results;
            if (SpellManager.FindSpell(Spell, out results))
                return results.Override != null ? results.Override.Cooldown : results.Original.Cooldown;
            return false;
        }
        #endregion

        #region Debuff Checks

        public bool debuffExists(int Debuff, WoWUnit onTarget)
        {
            if (onTarget != null)
            {
                WoWAura aura = onTarget.GetAllAuras().FirstOrDefault(a => a.SpellId == Debuff && a.CreatorGuid == Me.Guid);
                if (aura != null)
                {
                    return true;
                }
            }
            return false;
        }

        public double debuffTimeLeft(int Debuff, WoWUnit onTarget)
        {
            if (onTarget != null)
            {
                WoWAura aura = onTarget.GetAllAuras().FirstOrDefault(a =>
                    a.SpellId == Debuff
                    && a.CreatorGuid == Me.Guid);

                if (aura == null)
                {
                    return 0;
                }
                return aura.TimeLeft.TotalMilliseconds;
            }
            return 0;
        }

        public uint debuffStackCount(int Debuff, WoWUnit onTarget)
        {
            if (onTarget != null)
            {
                WoWAura aura = onTarget.GetAllAuras().FirstOrDefault(a =>
                    a.SpellId == Debuff
                    && a.CreatorGuid == Me.Guid);

                if (aura == null)
                {
                    return 0;
                }
                return aura.StackCount;
            }
            return 0;
        }
        public bool debuffExists(string Debuff, WoWUnit onTarget)
        {
            if (onTarget != null)
            {
                WoWAura aura = onTarget.GetAllAuras().FirstOrDefault(a => a.Name == Debuff && a.CreatorGuid == Me.Guid);
                if (aura != null)
                {
                    return true;
                }
            }
            return false;
        }

        public double debuffTimeLeft(string Debuff, WoWUnit onTarget)
        {
            if (onTarget != null)
            {
                WoWAura aura = onTarget.GetAllAuras().FirstOrDefault(a =>
                    a.Name == Debuff
                    && a.CreatorGuid == Me.Guid);

                if (aura == null)
                {
                    return 0;
                }
                return aura.TimeLeft.TotalMilliseconds;
            }
            return 0;
        }

        public uint debuffStackCount(string Debuff, WoWUnit onTarget)
        {
            if (onTarget != null)
            {
                WoWAura aura = onTarget.GetAllAuras().FirstOrDefault(a =>
                    a.Name == Debuff
                    && a.CreatorGuid == Me.Guid);

                if (aura == null)
                {
                    return 0;
                }
                return aura.StackCount;
            }
            return 0;
        }
        #endregion

        #region Target Checks
        public double targetDistance(WoWUnit onTarget)
        {
            if (onTarget != null)
            {
                var Results = onTarget.DistanceSqr;
                if (Results != null)
                    return onTarget.DistanceSqr;
            }
            return 0;
        }
        public double targetHP(WoWUnit onTarget)
        {
            if (onTarget != null)
            {
                var Results = onTarget.HealthPercent;
                if (Results != null)
                    return onTarget.HealthPercent;
            }
            return 0;
        }
        #endregion

        #region Timer Checks
        private int conv_Date2Timestam(DateTime _time)
        {
            var date1 = new DateTime(1970, 1, 1);
            DateTime date2 = _time;
            var ts = new TimeSpan(date2.Ticks - date1.Ticks);
            return (Convert.ToInt32(ts.TotalSeconds));
        }
        private uint current_life;
        private int current_time;
        private ulong guid;
        private uint first_life;
        private uint first_life_max;
        private int first_time;
        public long targetExistence(WoWUnit onTarget)
        {
            if (onTarget == null) return 0;
            if (Me.CurrentTarget.Name.Contains("Dummy")) return 9999;
            if (onTarget.CurrentHealth == 0 || onTarget.IsDead || !onTarget.IsValid || !onTarget.IsAlive)
                return 0;
            if (guid != onTarget.Guid)
            {
                guid = onTarget.Guid;
                first_life = onTarget.CurrentHealth;
                first_life_max = onTarget.MaxHealth;
                first_time = conv_Date2Timestam(DateTime.Now);
            }
            current_life = onTarget.CurrentHealth;
            current_time = conv_Date2Timestam(DateTime.Now);
            var time_diff = current_time - first_time;
            var hp_diff = first_life - current_life;
            if (hp_diff > 0)
            {
                var full_time = time_diff * first_life_max / hp_diff;
                var past_first_time = (first_life_max - first_life) * time_diff / hp_diff;
                var calc_time = first_time - past_first_time + full_time - current_time;
                if (calc_time < 1) calc_time = 99;
                var time_to_die = calc_time;
                var fight_length = full_time;
                return time_to_die;
            }
            if (hp_diff < 0)
            {
                guid = onTarget.Guid;
                first_life = onTarget.CurrentHealth;
                first_life_max = onTarget.MaxHealth;
                first_time = conv_Date2Timestam(DateTime.Now);
                return -1;
            }
            if (current_life == first_life_max)
                return 9999;
            return -1;
        }
        #endregion

        #region gottarget

        public bool gotTarget { get { return Me.GotTarget && Me.CurrentTarget != null && Me.CurrentTarget.Attackable && (!Me.CurrentTarget.IsDead && !Me.CurrentTarget.IsFriendly); } }

        #endregion gottarget

        #region spellcharges
        public int SpellCharges()
        {
            return Lua.GetReturnVal<int>("return GetSpellCharges(17962)", 0);
        }
        #endregion spellcharges

        #region Kind of target
        public bool IsWoWBoss(WoWUnit mytarget)
        {

            if (gotTarget
                && Me.CurrentTarget.CreatureRank == WoWUnitClassificationType.WorldBoss)
            {
                return true;
            }
            else if (gotTarget
                && target.IsBoss(mytarget))
            {
                return true;
            }
            else if (gotTarget
                && Me.CurrentTarget.MaxHealth >= (65 * 1000000))
            {
                return true;
            }
            else if (gotTarget
                    && Me.CurrentTarget.CreatureRank == WoWUnitClassificationType.RareElite
                    && Me.CurrentTarget.MaxHealth >= (Me.MaxHealth * CRSettingsBM.myPrefs.ElitesHealth)
                    && !Me.IsInInstance
                    && !Me.GroupInfo.IsInRaid)
            {
                return true;
            }
            else if (gotTarget
                     && Me.CurrentTarget.CreatureRank == WoWUnitClassificationType.Rare
                     && Me.CurrentTarget.MaxHealth >= (Me.MaxHealth * CRSettingsBM.myPrefs.ElitesHealth)
                     && !Me.IsInInstance
                     && !Me.GroupInfo.IsInRaid)
            {
                return true;
            }
            else if (gotTarget
                && Me.CurrentTarget.CreatureRank == WoWUnitClassificationType.Elite
                && Me.CurrentTarget.MaxHealth >= (Me.MaxHealth * CRSettingsBM.myPrefs.ElitesHealth)
                && !Me.IsInInstance
                && !Me.GroupInfo.IsInRaid)
            {
                return true;
            }
            else if (gotTarget
                && Me.CurrentTarget.Name.Contains("Training Dummy")
                && !Me.IsInInstance)
            {
                return true;
            }
            else if (gotTarget
                && Me.CurrentTarget.IsPlayer
                && !Me.CurrentTarget.IsFriendly)
            {
                return true;
            }
            return false;
        }

        #endregion Kind of Target

        #region speedbuffs
        public bool SpeedBuff
        {
            get
            {
                return buffExists("Heroism", Me)
                    || buffExists("Bloodlust", Me)
                    || buffExists("Time Warp", Me)
                    || buffExists("Ancient Hysteria", Me);
            }
        }
        #endregion speedbuffs

        #region check pulltargets
        public Composite checkTargets()
        {
            return new Decorator(ret => CRSettingsBM.myPrefs.Movement,
                new Action(ret =>
                {
                    if (Battlegrounds.IsInsideBattleground)
                    {
                        if (Me.GotTarget &&
                            Me.CurrentTarget.IsPet)
                        {
                            Blacklist.Add(Me.CurrentTarget, TimeSpan.FromDays(1));
                            Me.ClearTarget();
                        }

                        if (Me.GotTarget && Me.CurrentTarget.Mounted)
                        {
                            Blacklist.Add(Me.CurrentTarget, TimeSpan.FromMinutes(1));
                            Me.ClearTarget();
                        }
                    }

                    if (Me.CurrentTarget.Guid != lastGuid)
                    {
                        fightTimer.Reset();
                        lastGuid = Me.CurrentTarget.Guid;
                        Logging.Write(Colors.PaleGreen, "Killing " + Me.CurrentTarget.Name + " at distance " + System.Math.Round(Me.CurrentTarget.Distance).ToString() + ".");
                        pullTimer.Reset();
                        pullTimer.Start();

                    }
                    else
                    {
                        if (pullTimer.ElapsedMilliseconds > 30 * 1000)
                        {
                            Logging.Write(Colors.PaleGreen, "Cannot pull " + Me.CurrentTarget.Name + " now.  Blacklist for 3 minutes.");
                            Styx.CommonBot.Blacklist.Add(Me.CurrentTarget.Guid, System.TimeSpan.FromMinutes(3));
                        }
                    }
                    return RunStatus.Failure;
                }));
        }
        #endregion checkpulltargets

        #region bugged mobs
        public Composite checkBuggedMobs()
        {
            return new Decorator(ret => CRSettingsBM.myPrefs.Movement && gotTarget,
                new Action(ret =>
                {
                    if (Me.GotTarget && (!fightTimer.IsRunning || Me.CurrentTarget.Guid != lastGuid))
                    {
                        fightTimer.Reset();
                        fightTimer.Start();
                        lastGuid = Me.CurrentTarget.Guid;
                    }
                    if (Me.CurrentTarget != null
                        && !Me.CurrentTarget.IsPlayer
                        && !IsWoWBoss(Me.CurrentTarget)
                        && fightTimer.ElapsedMilliseconds > 30 * 1000
                        && Me.CurrentTarget.HealthPercent > 95)
                    {
                        Logging.Write(Colors.PaleGreen, " This " + Me.CurrentTarget.Name + " is a bugged mob.  Blacklisting for 1 min.");

                        Blacklist.Add(Me.CurrentTarget.Guid, TimeSpan.FromMinutes(1.00));
                        Me.ClearTarget();
                        SafeMove(WoWMovement.MovementDirection.Backwards, 3000);
                        lastGuid = 0;
                    }
                    if (Me.CurrentTarget != null
                        && fightTimer.ElapsedMilliseconds > 30 * 1000
                        && !Me.Combat)
                    {
                        Logging.Write(Colors.PaleGreen, "Take too long to engage " + Me.CurrentTarget.Name + " Blacklisting for 30 sec.");
                        Blacklist.Add(Me.CurrentTarget.Guid, TimeSpan.FromSeconds(30.00));
                        Me.ClearTarget();
                        SafeMove(WoWMovement.MovementDirection.Backwards, 3000);
                        lastGuid = 0;
                    }
                    return RunStatus.Failure;
                }));
        }

        private void SafeMove(WoWMovement.MovementDirection direction, int duration)
        {
            DateTime start = DateTime.Now;

            WoWMovement.Move(direction);

            while (IsInGame && Me.HealthPercent > 1)
            {
                Thread.Sleep(335);

                if (DateTime.Now.Subtract(start).Milliseconds < 300 || DateTime.Now.Subtract(start).Milliseconds >= duration)
                {
                    break;
                }

            }

            WoWMovement.MoveStop(direction);
        }
        private bool IsInGame
        {
            get
            {
                return StyxWoW.IsInGame;
            }
        }
        #endregion bugged mobs

        #region movement
        Composite createFacing()
        {
            return new Decorator(ret => Me.CurrentTarget != null && !Me.IsSafelyFacing(Me.CurrentTarget) && CRSettingsBM.myPrefs.Movement,
                new Action(ret =>
                {
                    if (!Me.IsSafelyFacing(Me.CurrentTarget))
                    {
                        Me.CurrentTarget.Face();
                    }
                    return RunStatus.Failure;
                }));
        }
        Composite createLignOfSight()
        {
            return new Decorator(ret => Me.CurrentTarget != null && !Me.CurrentTarget.InLineOfSight && CRSettingsBM.myPrefs.Movement,
                new Action(ret =>
                {
                    Logging.Write("Moving in lign of sight " + Me.CurrentTarget.Name);
                    while (!Me.CurrentTarget.InLineOfSight)
                    {
                        Navigator.MoveTo(StyxWoW.Me.CurrentTarget.Location);
                    }
                    return RunStatus.Failure;
                }));
        }
        Composite createMoveInRange()
        {
            return new Decorator(ret => Me.CurrentTarget != null && Me.CurrentTarget.Distance > 35 && CRSettingsBM.myPrefs.Movement,
                new Action(ret =>
                {
                    Logging.Write("Moving in range 35 " + Me.CurrentTarget.Name);
                    while (Me.CurrentTarget.Distance > 35)
                    {
                        Navigator.MoveTo(StyxWoW.Me.CurrentTarget.Location);
                    }
                    return RunStatus.Failure;
                }));
        }
        Composite createStopMove()
        {
            return new Decorator(ret => Me.CurrentTarget != null && Me.CurrentTarget.Distance <= 35 && CRSettingsBM.myPrefs.Movement,
                new Action(ret =>
                {
                    if (Me.CurrentTarget.Distance <= 35)
                    {
                        Navigator.PlayerMover.MoveStop();
                    }
                    return RunStatus.Failure;
                }));
        }
        #endregion movement

        #region AddCounting
        IEnumerable<WoWUnit> UnfriendlyUnits
        {
            get
            {

                return
                    ObjectManager.GetObjectsOfType<WoWUnit>(true, false).Where(u => !u.IsDead
                        && u.CanSelect
                        && u.Attackable
                        && !u.IsFriendly
                        && (Me.CurrentTarget != null && u.Location.Distance(Me.CurrentTarget.Location) <= 10)
                        && !u.Name.Contains("Dummy"));

            }
        }
        #endregion AddCounting

        #region findtarget
        Composite findTarget()
        {
            return new Decorator(ret => CRSettingsBM.myPrefs.Movement && (Me.CurrentTarget == null ||
                (Me.CurrentTarget != null
                    && Me.CurrentTarget.IsFriendly
                    || !Me.CurrentTarget.Attackable
                    || !Me.CurrentTarget.CanSelect)) && Me.Combat && CRSettingsBM.myPrefs.Movement,
                new Action(ret =>
                {
                    WoWUnit newTarget = (from o in ObjectManager.ObjectList
                                         where o is WoWUnit
                                         let unit = o.ToUnit()
                                         where (!unit.IsDead
                                            && unit.CanSelect
                                            && !unit.IsFriendly
                                            && !unit.IsCritter
                                            && !unit.IsPetBattleCritter
                                            && !Blacklist.Contains(unit.Guid, BlacklistFlags.All))
                                            || (unit.IsTargetingMeOrPet || unit.IsTargetingMyPartyMember || unit.IsTargetingMyRaidMember)
                                         orderby unit.Location.Distance(Me.Location)
                                         select unit)
                                   .FirstOrDefault();

                    if (newTarget != null)
                    {
                        Logging.Write(Colors.Red, "Found new target " + newTarget.Name);
                        newTarget.Target();
                        SpellManager.Cast("Auto Shot");
                    }
                    return RunStatus.Failure;
                }));
        }

        public void ensureTarget()
        {
            WoWUnit newTarget = (from o in ObjectManager.ObjectList
                                 where o is WoWUnit
                                 let unit = o.ToUnit()
                                 where (unit.CanSelect
                                  && !unit.IsFriendly
                                  && !unit.IsCritter
                                  && !unit.IsPetBattleCritter
                                  && !Blacklist.Contains(unit.Guid, BlacklistFlags.All))
                                  || (unit.IsTargetingMeOrPet || unit.IsTargetingMyPartyMember || unit.IsTargetingMyRaidMember)
                                 orderby unit.Location.Distance(Me.Location)
                                 select unit)
                                   .FirstOrDefault();
            if (newTarget != null)
            {
                Logging.Write(Colors.Red, "Found new target " + newTarget.Name);
                newTarget.Target();
            }
        }
        #endregion findtarget

        #region paused
        Composite IsPaused()
        {
            return new Decorator(ret => Paused || buffExists(FEIGN_DEATH, Me) || (Me.Mounted && !CRSettingsBM.myPrefs.Movement),
                new Action(ret =>
                {
                    if (Me.Combat && Me.CurrentTarget != null)
                    {
                        Lua.DoString("StopAttack()");
                        Me.ClearTarget();
                    }
                    return;
                }));
        }
        #endregion paused

        #region healthstone
        Composite useHealthStone()
        {
            return new Decorator(ret => gotTarget
                && LastSpell != "healthstone",
                new Action(ret =>
            {
                WoWItem hstone = Me.BagItems.FirstOrDefault(h => h.Entry == 5512);

                if (hstone != null && hstone.CooldownTimeLeft.TotalMilliseconds <= 0)
                {
                    hstone.Use();
                    Logging.Write(Colors.BlanchedAlmond, "Using Healthstone");
                    LastSpell = "healthstone";
                }
                return RunStatus.Failure;
            }));
        }
        #endregion healthstone

        #region flask
        Composite useAgiFlask()
        {
            return new Decorator(ret => gotTarget
                && CRSettingsBM.myPrefs.whenToUseFlask != CRSettingsBM.WhenToUseFlask.Manual
                && Me.Combat
                && Me.CurrentTarget.Distance <= 40
                && !buffExists(FLASK_OF_SPRING_BLOSSOMS, Me)
                && ((CRSettingsBM.myPrefs.whenToUseFlask == CRSettingsBM.WhenToUseFlask.Raids_but_not_LFR && !Me.GroupInfo.IsInLfgParty && Me.GroupInfo.IsInRaid)
                || (CRSettingsBM.myPrefs.whenToUseFlask == CRSettingsBM.WhenToUseFlask.Instances && Me.IsInInstance))
                && LastSpell != "agiflask",
                new Action(ret =>
            {
                WoWItem flask = Me.BagItems.FirstOrDefault(h => h.Entry == 76084);

                if (flask != null && flask.CooldownTimeLeft.TotalMilliseconds <= 0)
                {
                    flask.Use();
                    Logging.Write(Colors.BlanchedAlmond, "Using " + flask.Name);
                    LastSpell = "agiflask";
                }
                return RunStatus.Failure;
            }));
        }
        #endregion flask

        #region alchemy flask
        Composite useAlchemyFlask()
        {
            return new Decorator(ret => CRSettingsBM.myPrefs.useAlchemyFlask
                && !buffExists(FLASK_OF_SPRING_BLOSSOMS, Me)
                && !buffExists(VISIONS_OF_INSANITY, Me)
                && !buffExists("Enhanced Agility", Me)
                && LastSpell != "alchemy",
                new Action(ret =>
                {
                    WoWItem alchflask = Me.BagItems.FirstOrDefault(h => h.Entry == 75525);

                    if (alchflask != null)
                    {
                        alchflask.Use();
                        Logging.Write(Colors.LightBlue, "Using Alchemist's Flask");
                        LastSpell = "alchemy";
                    }
                    return RunStatus.Failure;
                }));
        }
        #endregion alchemy flask

        Composite Trinket1()
        {
            return new Decorator(ret => gotTarget
                    && (CRSettingsBM.myPrefs.trinket1 == CRSettingsBM.CooldownPrefs.OnCoolDown
                    || (CRSettingsBM.myPrefs.trinket1 == CRSettingsBM.CooldownPrefs.Bosses && IsWoWBoss(Me.CurrentTarget)))
                    && LastSpell != "trinket1"
                    && LastSpell != "trinket2",
                new Action(ret =>
                {
                    var firstTrinket = StyxWoW.Me.Inventory.Equipped.Trinket1;

                    if (firstTrinket != null && CanUseEquippedItem(firstTrinket))
                    {
                        firstTrinket.Use();
                        Logging.Write(Colors.PaleGreen, "Using 1st trinket");
                        LastSpell = "trinket1";
                    }
                    return RunStatus.Failure;
                }));
        }
        Composite Trinket2()
        {
            return new Decorator(ret => gotTarget
                    && (CRSettingsBM.myPrefs.trinket2 == CRSettingsBM.CooldownPrefs.OnCoolDown
                    || (CRSettingsBM.myPrefs.trinket2 == CRSettingsBM.CooldownPrefs.Bosses && IsWoWBoss(Me.CurrentTarget)))
                    && LastSpell != "trinket1"
                    && LastSpell != "trinket2",
                new Action(ret =>
                {
                    var secondTrinket = StyxWoW.Me.Inventory.Equipped.Trinket2;

                    if (secondTrinket != null && CanUseEquippedItem(secondTrinket))
                    {
                        secondTrinket.Use();
                        Logging.Write(Colors.PaleGreen, "Using 2nd trinket");
                        LastSpell = "trinket2";
                    }
                    return RunStatus.Failure;
                }));
        }
        Composite Gloves()
        {
            return new Decorator(ret => gotTarget
                    && ((CRSettingsBM.myPrefs.gloves == CRSettingsBM.CooldownPrefs.OnCoolDown && targetExistence(Me.CurrentTarget) >= 30 && !IsWoWBoss(Me.CurrentTarget))
                    || (CRSettingsBM.myPrefs.gloves == CRSettingsBM.CooldownPrefs.Bosses && IsWoWBoss(Me.CurrentTarget)))
                    && LastSpell != "gloves",
                new Action(ret =>
                {
                    var engiGloves = StyxWoW.Me.Inventory.Equipped.Hands;

                    if (engiGloves != null && CanUseEquippedItem(engiGloves))
                    {
                        engiGloves.Use();
                        Logging.Write(Colors.PaleGreen, "Using Engineer Gloves");
                        LastSpell = "gloves";
                    }
                    return RunStatus.Failure;
                }));
        }
        Composite StatsPotion()
        {
            return new Decorator(ret => gotTarget
                    && ((CRSettingsBM.myPrefs.whenToUseStatsPotion == CRSettingsBM.PotionsPrefs.AllBosses && IsWoWBoss(Me.CurrentTarget))
                    || (CRSettingsBM.myPrefs.whenToUseStatsPotion == CRSettingsBM.PotionsPrefs.RaidBosses && IsWoWBoss(Me.CurrentTarget) && Me.GroupInfo.IsInRaid))
                    && LastSpell != "virmen",
                new Action(ret =>
                {
                    WoWItem potion = Me.BagItems.FirstOrDefault(h => h.Entry == 76089);


                    if (potion != null && potion.CooldownTimeLeft.TotalMilliseconds <= 0)
                    {
                        potion.Use();
                        Logging.Write(Colors.BlanchedAlmond, "Using " + potion.Name);
                        LastSpell = "virmen";
                    }
                    return RunStatus.Failure;
                }));
        }
        Composite CrystalOfInsanity()
        {
            return new Decorator(ret => CRSettingsBM.myPrefs.useCrystal
                && !buffExists(FLASK_OF_SPRING_BLOSSOMS, Me)
                && LastSpell != "crystal",
                new Action(ret =>
                {
                    WoWItem crystal = Me.BagItems.FirstOrDefault(h => h.Entry == 86569);


                    if (crystal != null && crystal.CooldownTimeLeft.TotalMilliseconds <= 0)
                    {
                        crystal.Use();
                        Logging.Write(Colors.BlanchedAlmond, "Using " + crystal.Name);
                        LastSpell = "crystal";
                    }
                    return RunStatus.Failure;
                }));
        }

        #region can use equipped items
        private static bool CanUseEquippedItem(WoWItem item)
        {
            string itemSpell = Lua.GetReturnVal<string>("return GetItemSpell(" + item.Entry + ")", 0);
            if (string.IsNullOrEmpty(itemSpell))
            {
                return false;
            }
            return item.Usable && item.Cooldown <= 0;
        }
        #endregion can use equipped items

        #region eatfood
        Composite EatFood()
        {
            return new Decorator(ret => Me.HealthPercent <= CRSettingsBM.myPrefs.eatFood
                && !Me.IsDead
                && !Me.IsGhost
                && !Me.IsSwimming,
                new Action(ret =>
                {
                    Styx.CommonBot.Rest.Feed();
                }));
        }
        #endregion eatfood

        #region overlayed
        public bool IsOverlayed(int spellID)
        {
            return Lua.GetReturnVal<bool>("return IsSpellOverlayed(" + spellID + ")", 0);
        }
        #endregion overlayed

        #region DoAoe
        public bool DoAoe
        {
            get { return SpellManager.HasSpell(MULTI_SHOT) && UnfriendlyUnits.Count() >= CRSettingsBM.myPrefs.startAoe && !PauseAoe; }
        }
        #endregion DoAoe
    }
}
